﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using UnityEngine;
using Voxel2Unity;

public static class VoxFileExt
{
    private static Color[] DefaultPallete;

    static VoxFileExt()
    {
        Color[] colorArray = new Color[0x100];
        int index = 0;
        for (int i = 10; i >= 0; i -= 2)
        {
            for (int num3 = 10; num3 >= 0; num3 -= 2)
            {
                for (int num4 = 10; num4 >= 0; num4 -= 2)
                {
                    if (((i + num3) + num4) != 0)
                    {
                        colorArray[index] = new Color(((float) i) / 10f, ((float) num3) / 10f, ((float) num4) / 10f);
                        index++;
                    }
                }
            }
        }
        for (int j = 14; j > 0; j--)
        {
            if ((j % 3) != 0)
            {
                colorArray[index] = new Color(((float) j) / 15f, 0f, 0f);
                index++;
            }
        }
        for (int k = 14; k > 0; k--)
        {
            if ((k % 3) != 0)
            {
                colorArray[index] = new Color(0f, ((float) k) / 15f, 0f);
                index++;
            }
        }
        for (int m = 14; m > 0; m--)
        {
            if ((m % 3) != 0)
            {
                colorArray[index] = new Color(0f, 0f, ((float) m) / 15f);
                index++;
            }
        }
        for (int n = 14; n > 0; n--)
        {
            if ((n % 3) != 0)
            {
                colorArray[index] = new Color(((float) n) / 15f, ((float) n) / 15f, ((float) n) / 15f);
                index++;
            }
        }
        colorArray[0xff] = new Color(0f, 0f, 0f, 1f);
        DefaultPallete = colorArray;
    }

    private static HashSet<int> GetUsedPalatteIndices(List<VoxData> voxDatas)
    {
        HashSet<int> set = new HashSet<int>();
        foreach (VoxData data in voxDatas)
        {
            for (int i = 0; i < data.SizeX; i++)
            {
                for (int j = 0; j < data.SizeY; j++)
                {
                    for (int k = 0; k < data.SizeZ; k++)
                    {
                        int item = data.Voxels[i, j, k];
                        if (item != 0)
                        {
                            set.Add(item);
                        }
                    }
                }
            }
        }
        return set;
    }

    public static List<VoxData> LoadVoxel(string path, out Dictionary<int, VoxMaterial> materials)
    {
        return LoadVoxel(Util.FileToByte(path), out materials);
    }

    public static List<VoxData> LoadVoxel(byte[] _dataBytes, out Dictionary<int, VoxMaterial> materials)
    {
        materials = new Dictionary<int, VoxMaterial>();
        if (((_dataBytes[0] != 0x56) || (_dataBytes[1] != 0x4f)) || ((_dataBytes[2] != 0x58) || (_dataBytes[3] != 0x20)))
        {
            Debug.LogError("Error Magic Number");
            return null;
        }
        using (MemoryStream stream = new MemoryStream(_dataBytes))
        {
            using (BinaryReader reader = new BinaryReader(stream))
            {
                reader.ReadInt32();
                byte[] buffer = reader.ReadBytes(4);
                byte[] buffer2 = reader.ReadBytes(4);
                if (((buffer2[0] != 0x4d) || (buffer2[1] != 0x41)) || ((buffer2[2] != 0x49) || (buffer2[3] != 0x4e)))
                {
                    Debug.LogError("Error main ID");
                    return null;
                }
                List<VoxData> source = new List<VoxData>();
                Color[] defaultPallete = null;
                int count = reader.ReadInt32();
                int num2 = reader.ReadInt32();
                reader.ReadBytes(count);
                HashSet<int> usedPalatteIndices = null;
                int num3 = 0;
                while (num3 < num2)
                {
                    buffer2 = reader.ReadBytes(4);
                    if (((buffer2[0] == 0x53) && (buffer2[1] == 0x49)) && ((buffer2[2] == 90) && (buffer2[3] == 0x45)))
                    {
                        VoxData item = new VoxData {
                            Version = buffer
                        };
                        source.Add(item);
                        num3 += ReadSizeChunk(reader, item);
                    }
                    else
                    {
                        if (((buffer2[0] == 0x58) && (buffer2[1] == 0x59)) && ((buffer2[2] == 90) && (buffer2[3] == 0x49)))
                        {
                            VoxData data2 = source.Last<VoxData>();
                            num3 += ReadVoxelChunk(reader, data2);
                            continue;
                        }
                        if (((buffer2[0] == 0x52) && (buffer2[1] == 0x47)) && ((buffer2[2] == 0x42) && (buffer2[3] == 0x41)))
                        {
                            defaultPallete = new Color[0x100];
                            num3 += ReadPalattee(reader, defaultPallete);
                            continue;
                        }
                        if (((buffer2[0] == 0x4d) && (buffer2[1] == 0x41)) && ((buffer2[2] == 0x54) && (buffer2[3] == 0x54)))
                        {
                            if (usedPalatteIndices == null)
                            {
                                usedPalatteIndices = GetUsedPalatteIndices(source);
                            }
                            num3 += ReadMatChunk(reader, materials, usedPalatteIndices);
                            continue;
                        }
                        int num4 = reader.ReadInt32();
                        int num5 = reader.ReadInt32();
                        reader.ReadBytes(num4 + num5);
                        num3 += (num4 + num5) + 12;
                    }
                }
                if (defaultPallete == null)
                {
                    defaultPallete = DefaultPallete;
                }
                foreach (VoxData data3 in source)
                {
                    data3.Palatte = defaultPallete;
                }
                return source;
            }
        }
    }

    private static int ReadMatChunk(BinaryReader _br, Dictionary<int, VoxMaterial> materials, HashSet<int> usedPalatteIndices)
    {
        int num = _br.ReadInt32();
        int num2 = _br.ReadInt32();
        int item = _br.ReadInt32();
        VoxMaterial.Type type = (VoxMaterial.Type) _br.ReadInt32();
        float num4 = _br.ReadSingle();
        uint num5 = _br.ReadUInt32();
        int num6 = (num - 0x10) / 4;
        float[] numArray = new float[num6];
        for (int i = 0; i < num6; i++)
        {
            numArray[i] = _br.ReadSingle();
        }
        if (usedPalatteIndices.Contains(item))
        {
            VoxMaterial material = new VoxMaterial {
                materialType = type,
                materialWeight = num4,
                propertyBits = num5,
                normalizedPropertyValues = numArray
            };
            materials.Add(item, material);
        }
        return ((num + num2) + 12);
    }

    private static int ReadPalattee(BinaryReader _br, Color[] _colors)
    {
        int num = _br.ReadInt32();
        int count = _br.ReadInt32();
        for (int i = 0; i < 0x100; i++)
        {
            _colors[i] = new Color(((float) _br.ReadByte()) / 255f, ((float) _br.ReadByte()) / 255f, ((float) _br.ReadByte()) / 255f, ((float) _br.ReadByte()) / 255f);
        }
        if (count > 0)
        {
            _br.ReadBytes(count);
        }
        return ((num + count) + 12);
    }

    private static int ReadSizeChunk(BinaryReader _br, VoxData _mainData)
    {
        int num = _br.ReadInt32();
        int count = _br.ReadInt32();
        _mainData.SizeX = _br.ReadInt32();
        _mainData.SizeY = _br.ReadInt32();
        _mainData.SizeZ = _br.ReadInt32();
        _mainData.Voxels = new int[_mainData.SizeX, _mainData.SizeY, _mainData.SizeZ];
        if (count > 0)
        {
            _br.ReadBytes(count);
        }
        return ((num + count) + 12);
    }

    private static int ReadVoxelChunk(BinaryReader _br, VoxData _mainData)
    {
        int num = _br.ReadInt32();
        int count = _br.ReadInt32();
        int num3 = _br.ReadInt32();
        for (int i = 0; i < num3; i++)
        {
            int num5 = _br.ReadByte();
            int num6 = _br.ReadByte();
            int num7 = _br.ReadByte();
            byte num8 = _br.ReadByte();
            _mainData.Voxels[num5, num6, num7] = num8;
        }
        if (count > 0)
        {
            _br.ReadBytes(count);
        }
        return ((num + count) + 12);
    }
}

